﻿#region Header

/*
    This file is part of nDoctor Light

    NDoctor is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    NDoctor is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with NDoctor.  If not, see <http://www.gnu.org/licenses/>.
*/

#endregion Header

namespace Probel.Ldoc.Dal.Services
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;

    using AutoMapper;

    using NHibernate;
    using NHibernate.Linq;

    using Probel.Ldoc.Dal.Configuration;
    using Probel.Ldoc.Dal.Entities;
    using Probel.Ldoc.Services.Dto;

    internal class PatientUpdater : IDisposable
    {
        #region Fields

        private readonly ISession Session;

        #endregion Fields

        #region Constructors

        public PatientUpdater()
        {
            this.Session = DalManager.SessionFactory.OpenSession();
        }

        #endregion Constructors

        #region Methods

        public void Dispose()
        {
            this.Session.Dispose();
        }

        public void Update(ExpandedPatientDto patient)
        {
            var toUpdate = this.Session.Get<Patient>(patient.Id);
            toUpdate = Mapper.Map<ExpandedPatientDto, Patient>(patient, toUpdate);

            this.UpdateDoctors(patient.Doctors, toUpdate);
            this.UpdateTags(patient.SearchTags, toUpdate);

            toUpdate.Profession = this.GetProfesstion(patient);
            toUpdate.Insurance = this.GetInsurance(patient);
            toUpdate.Practice =this.GetPractice(patient);
            toUpdate.Reputation = this.GetReputation(patient);

            this.Session.Update(toUpdate);
            this.Session.Flush();
        }

        private void ClearAllDoctors(Patient patient)
        {
            foreach (var doctor in patient.Doctors) { doctor.Patients.Remove(patient); }
            patient.Doctors.Clear();
        }

        private Insurance GetInsurance(ExpandedPatientDto patient)
        {
            return (patient.Insurance != null)
                ? this.Session.Get<Insurance>(patient.Insurance.Id)
                : null;
        }

        private Practice GetPractice(ExpandedPatientDto patient)
        {
            return (patient.Practice != null)
                ? this.Session.Get<Practice>(patient.Practice.Id)
                : null;
        }

        private Profession GetProfesstion(ExpandedPatientDto patient)
        {
            return (patient.Profession != null)
                ? this.Session.Get<Profession>(patient.Profession.Id)
                : null;
        }

        private Reputation GetReputation(ExpandedPatientDto patient)
        {
            return (patient.Reputation != null)
                ? this.Session.Get<Reputation>(patient.Reputation.Id)
                : null;
        }

        private void UpdateDoctors(IEnumerable<DoctorCardDto> doctors, Patient patient)
        {
            var doctorsId = (from d in doctors
                             select d.Id).ToList();

            this.ClearAllDoctors(patient);
            patient.Doctors = (from d in this.Session.Query<Doctor>()
                               where doctorsId.Contains(d.Id)
                               select d).ToList();

            foreach (var doctor in patient.Doctors)
            {
                var exists = (from p in doctor.Patients
                              where p.Id == patient.Id
                              select p).Count() > 0;
                if (!exists) { doctor.Patients.Add(patient); }
                //else { doctor.Patients.Remove(patient); }
            }
        }

        private void UpdateTags(IEnumerable<TagDto> tags, Patient patientE)
        {
            var tagsIds = (from t in tags
                           select t.Id).ToList();

            patientE.SearchTags = (from t in this.Session.Query<SearchTag>()
                                   where tagsIds.Contains(t.Id)
                                   select t).ToList();
        }

        #endregion Methods
    }
}